auto_fix_high
Smart Highlighter
Preview
let currentSmartRecommendations = []; function updateSmartColors() { const activeColor = currentSmartRecommendations.find(c => c.toLowerCase() === appState.color.toLowerCase()) || currentSmartRecommendations[0]; document.getElementById('sc-preview-highlight').style.backgroundColor = activeColor; } // --- Context Toolbar Actions --- function updateContextToolbar() { const tb = document.getElementById('context-toolbar'); if(!tb) return; if (appState.selectedStrokeIdx !== null && appState.selectedStrokeIdx !== undefined && appState.tool === 'select') { tb.classList.remove('-translate-y-20', 'opacity-0', 'pointer-events-none'); const colorPicker = document.getElementById('context-color'); colorPicker.value = appState.history[appState.selectedStrokeIdx].color; } else { tb.classList.add('-translate-y-20', 'opacity-0', 'pointer-events-none'); } } function modSelectedSize(delta) { if(appState.selectedStrokeIdx === null || appState.selectedStrokeIdx === undefined) return; let s = appState.history[appState.selectedStrokeIdx]; s.size = Math.max(2, s.size + delta); if(window.p5inst) window.p5inst.redrawHistory(); } function modSelectedColor(hex) { if(appState.selectedStrokeIdx === null || appState.selectedStrokeIdx === undefined) return; appState.history[appState.selectedStrokeIdx].color = hex; if(window.p5inst) window.p5inst.redrawHistory(); } function deleteSelected() { if(appState.selectedStrokeIdx === null || appState.selectedStrokeIdx === undefined) return; appState.history.splice(appState.selectedStrokeIdx, 1); appState.selectedStrokeIdx = null; updateContextToolbar(); if(window.p5inst) window.p5inst.redrawHistory(); } // --- UI Functions --- function setTool(toolName) { if(appState.isPlaying) return; appState.tool = toolName; appState.selectedStrokeIdx = null; updateContextToolbar(); if(window.p5inst) window.p5inst.redrawHistory(); document.querySelectorAll('.tool-btn').forEach(btn => { btn.classList.remove('active'); if(btn.dataset.tool === toolName) { btn.classList.add('active'); } }); const opSlider = document.getElementById('opacity-slider'); if (toolName === 'highlighter' || toolName === 'wetMarker') appState.opacity = 50; else if (toolName === 'brushPen') appState.opacity = 80; else if (toolName === 'chisel' || toolName === 'fine' || toolName === 'dryErase' || toolName === 'calligraphy' || toolName === 'paintMarker') appState.opacity = 95; else if (toolName === 'eraser') appState.opacity = 100; if (opSlider) { opSlider.value = appState.opacity; document.getElementById('opacity-val').innerText = appState.opacity + '%'; } } // ========================================== // P5.JS ENGINE (Instance Mode) // ========================================== const sketch = (p) => { const LOGICAL_W = 1920; const LOGICAL_H = 1080; let mainCanvas; // Interaction State let isDrawing = false; let isDraggingSelection = false; let dragLastX = 0, dragLastY = 0; let currentStroke = null; function handlePointerDown(e) { if (appState.isPlaying || appState.isExporting) return; e.preventDefault(); mainCanvas.elt.setPointerCapture(e.pointerId); const pos = getScaledPos(e); if (appState.tool === 'select') { let hitIdx = null; for (let i = appState.history.length - 1; i >= 0; i--) { let stroke = appState.history[i]; let hit = stroke.points.some(pt => p.dist(pos.x, pos.y, pt.x, pt.y) <= (stroke.size/2 + 10)); if (hit) { hitIdx = i; break; } } appState.selectedStrokeIdx = hitIdx; updateContextToolbar(); p.redrawHistory(); if(hitIdx !== null) { isDraggingSelection = true; dragLastX = pos.x; dragLastY = pos.y; } return; } isDrawing = true; pX = pos.x; pY = pos.y; function handlePointerMove(e) { if (appState.isPlaying || appState.isExporting) return; e.preventDefault(); const pos = getScaledPos(e); if (appState.tool === 'select' && isDraggingSelection && appState.selectedStrokeIdx !== null && appState.selectedStrokeIdx !== undefined) { let dx = pos.x - dragLastX; let dy = pos.y - dragLastY; let stroke = appState.history[appState.selectedStrokeIdx]; stroke.points.forEach(pt => { pt.x += dx; pt.y += dy; pt.px += dx; pt.py += dy; }); dragLastX = pos.x; dragLastY = pos.y; p.redrawHistory(); return; } if (!isDrawing) return; let now = p.millis(); function handlePointerUp(e) { if (appState.tool === 'select') { isDraggingSelection = false; } if (!isDrawing) return; isDrawing = false; p.redrawHistory = () => { p.clearCanvas(); p.push(); p.translate(appState.cameraX, appState.cameraY); p.scale(appState.cameraZoom); for (let i = 0; i < appState.history.length; i++) { let stroke = appState.history[i]; for (let pt of stroke.points) { drawBrushSegment(p, pt, stroke, 1.0); } if (i === appState.selectedStrokeIdx && appState.tool === 'select') { let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity; stroke.points.forEach(pt => { let r = stroke.size / 2; minX = Math.min(minX, pt.x - r); minY = Math.min(minY, pt.y - r); maxX = Math.max(maxX, pt.x + r); maxY = Math.max(maxY, pt.y + r); }); let pad = 8; p.push(); p.noFill(); p.stroke('#0ea5e9'); // Visual highlight p.strokeWeight(2 / appState.cameraZoom); p.drawingContext.setLineDash([8 / appState.cameraZoom, 8 / appState.cameraZoom]); p.rect(minX - pad, minY - pad, maxX - minX + pad*2, maxY - minY + pad*2); p.pop(); } } p.pop(); }; p.getTotalTime = () => {